<template>
  <div class="menu-modal">
    <el-dialog v-model="dialogVisible" :title="dialogTitle" width="640" center @closed="onClosed">
      <el-form ref="formRef" :model="menuForm" :rules="menuFormRules" label-width="auto">
        <el-form-item label="上级菜单:" prop="parentId">
          <el-tree-select
            v-model="menuForm.parentId"
            :data="menuTreeSelectData"
            check-strictly
            default-expand-all
            :render-after-expand="false"
          />
        </el-form-item>
        <el-form-item label="菜单名称:" prop="menuName">
          <el-input v-model="menuForm.menuName" />
        </el-form-item>
        <el-form-item label="菜单类型:" prop="menuType">
          <el-radio-group v-model="menuForm.menuType">
            <el-radio :value="0">目录</el-radio>
            <el-radio :value="1">菜单</el-radio>
            <el-radio :value="2">按钮</el-radio>
          </el-radio-group>
        </el-form-item>
        <el-form-item label="菜单地址:" prop="path">
          <el-input v-model="menuForm.path" />
        </el-form-item>
        <el-form-item label="权限标识:" prop="menuCode">
          <el-input v-model="menuForm.menuCode" />
        </el-form-item>
        <el-form-item label="排序:" prop="sort">
          <el-input v-model.number="menuForm.sort" />
        </el-form-item>
        <el-form-item label="菜单图标:" prop="menuIcon" style="height: fit-content">
          <picture-upload :picture-list="pictureList" @on-success="onUploadSuccess" />
        </el-form-item>
      </el-form>
      <template #footer>
        <div class="dialog-footer">
          <el-button class="btn" @click="dialogVisible = false">取消</el-button>
          <el-button class="btn" type="primary" color="var(--color-primary)" @click="handleConfirm">确认</el-button>
        </div>
      </template>
    </el-dialog>
  </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed } from "vue"
import { showErrorToast } from "@/utils/toast"
import { getMenuById } from "@/api/menu"
import { menuTypeEnum } from "@/enums/menu"
import PictureUpload from "@/components/business/PictureUpload.vue"
import type { FormInstance, FormRules } from "element-plus"

interface MenuForm {
  parentId: number
  menuName: string
  menuCode: string
  path: string
  menuType: number
  sort: number
  menuIcon: string
}

interface TreeSelectOption {
  value: number
  label: string
  children?: TreeSelectOption[]
  disabled?: boolean
}

const props = defineProps<{
  menuList: MenuTreeResponse[]
}>()

const emit = defineEmits<{
  create: [value: MenuCreateRequest]
  edit: [value: MenuEditRequest]
}>()

const formRef = ref<FormInstance | null>(null)

const dialogVisible = ref(false)
// 判断是新增还是编辑
const isEdit = ref(false)
// 编辑回显的菜单
const menu = ref<MenuResponse | null>(null)
const pictureList = ref<string[]>([])

const menuForm = reactive<MenuForm>({
  parentId: 0,
  menuName: "",
  menuCode: "",
  path: "",
  menuType: menuTypeEnum.DIRECTORY,
  sort: 0,
  menuIcon: ""
})
const menuFormRules = reactive<FormRules<MenuForm>>({
  menuName: [{ required: true, message: "请输入菜单名称", trigger: "blur" }],
  menuCode: [{ required: true, message: "请输入权限标识", trigger: "blur" }],
  path: [{ required: true, message: "请输入菜单地址", trigger: "blur" }],
  menuType: [{ required: true, message: "请选择菜单类型", trigger: "change" }],
  sort: [{ required: true, message: "请输入排序", trigger: "blur" }]
})

const dialogTitle = computed(() => {
  return isEdit.value ? "编辑菜单" : "新增菜单"
})

/**
 * 上级菜单数据
 */
const menuTreeSelectData = computed<TreeSelectOption[]>(() => {
  return [{ value: 0, label: "主目录", children: [] }, ...buildTreeSelectData(props.menuList)]
})

/**
 * 递归构造菜单树结构
 *
 * @param items 菜单列表
 * @param parentId 父 id
 */
const buildTreeSelectData = (items: MenuTreeResponse[]): TreeSelectOption[] => {
  return items
    .filter((item) => item.menuType !== menuTypeEnum.BUTTON)
    .map((item) => ({
      value: item.id,
      label: item.menuName,
      disabled: item.id === menu.value?.id,
      children: buildTreeSelectData(item.children || [])
    }))
}

const handleConfirm = () => {
  formRef.value?.validate((valid: boolean) => {
    if (valid) {
      if (isEdit.value) {
        if (!menu.value) return
        emit("edit", { ...menu.value, ...menuForm })
      } else {
        emit("create", { ...menuForm })
      }
    }
  })
}

/**
 * 上传菜单图标成功的回调
 *
 * @param fileUrl 图标地址
 */
const onUploadSuccess = (fileUrl: string) => {
  pictureList.value = [fileUrl]
  menuForm.menuIcon = fileUrl
}

/**
 * 打开弹窗
 *
 * @param flag 是否编辑
 * @param id 菜单 id
 */
const openModal = async (flag: boolean, id?: number) => {
  dialogVisible.value = true
  isEdit.value = flag

  if (flag && id) {
    try {
      const res = await getMenuById({ id })
      if (res.data) {
        menu.value = res.data
        menuForm.parentId = res.data.parentId
        menuForm.menuName = res.data.menuName
        menuForm.menuType = res.data.menuType
        menuForm.path = res.data.path
        menuForm.menuCode = res.data.menuCode
        menuForm.menuIcon = res.data.menuIcon
        menuForm.sort = res.data.sort
      }
    } catch (error: any) {
      showErrorToast(error.message)
    }
  }
}

const closeModal = () => {
  dialogVisible.value = false
}

const onClosed = () => {
  menu.value = null
  pictureList.value = []
  formRef.value?.resetFields()
  formRef.value?.clearValidate()
}

defineExpose({
  openModal,
  closeModal
})
</script>

<style lang="scss" scoped></style>
